package com.example.spring.statmachine.example.aspect;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.db.sql.Order;
import com.example.spring.statmachine.example.annotation.StateMachineAnno;
import com.example.spring.statmachine.example.bo.ExtendedVariablesBO;
import com.example.spring.statmachine.example.domain.TbOrder;
import com.example.spring.statmachine.example.enums.OrderStatusChangeEventEnum;
import com.example.spring.statmachine.example.enums.OrderStatusEnum;
import com.example.spring.statmachine.example.utils.SpelUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.messaging.Message;
import org.springframework.statemachine.StateMachine;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @author zhangwenxue
 */
@Component
@Aspect
public class StateMachineAspect {

    public static final Logger logger = LoggerFactory.getLogger(StateMachineAspect.class);

    @Resource
    private StateMachine<OrderStatusEnum, OrderStatusChangeEventEnum> orderStateMachine;



    @Pointcut("@annotation( com.example.spring.statmachine.example.annotation.StateMachineAnno)")
    private void stateMachinePointCut() {
    }



    @Around("stateMachinePointCut()")
    public Object stateMachineAround(ProceedingJoinPoint pjp) throws Throwable {
        //获取参数
        Object[] args = pjp.getArgs();
        logger.info("StateMachineAspect#参数args:{}", args);
        //获取方法
        Method method = ((MethodSignature) pjp.getSignature()).getMethod();
        if (method.isAnnotationPresent(StateMachineAnno.class)){
            // 获取stateMachineAnno注解
            StateMachineAnno stateMachineAnno = method.getAnnotation(StateMachineAnno.class);
            String keyExpression = stateMachineAnno.keyExpression();
            String key = stateMachineAnno.key();
            // 获取所有参数名称
            String[] parameterNames = new LocalVariableTableParameterNameDiscoverer()
                    .getParameterNames(((MethodSignature) pjp.getSignature()).getMethod());
            List<String> valeBySpelList;
            try {
                valeBySpelList = SpelUtils.getValeBySpel(keyExpression, parameterNames, args);
                if (CollectionUtil.isEmpty(valeBySpelList)){
                    logger.error("StateMachineAspect#stateMachineAround,未获取解析到Spel参数异常:keyExpression{}",keyExpression);
                    throw new RuntimeException("未获取解析到Spel参数异常");
                }
            }catch (Exception e){
                e.printStackTrace();
                throw e;
            }
            try {
                Object proceed = pjp.proceed();
                orderStateMachine.getExtendedState().getVariables().put(key + valeBySpelList.get(0), new ExtendedVariablesBO(Boolean.TRUE));
                return proceed;
            }catch (Exception e){
                logger.error("StateMachineAspect#stateMachineAround#exception:{}", e.getMessage(),e);
                orderStateMachine.getExtendedState().getVariables().put(key + valeBySpelList.get(0),
                        new ExtendedVariablesBO(Boolean.FALSE,e.getMessage()));
                throw e;
            }
        }else {
            return pjp.proceed();
        }
    }

}
